package com.ydlclass.channelHandler.handler;

import com.ydlclass.ServiceConfig;
import com.ydlclass.YrpcBootstrap;
import com.ydlclass.enumeration.RequestType;
import com.ydlclass.enumeration.ResponseCode;
import com.ydlclass.transport.message.RequestPayload;
import com.ydlclass.transport.message.YrpcRequest;
import com.ydlclass.transport.message.YrpcResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Author duWenJian
 * @Date 2023/11/2 10:09
 * @Version 1.0
 */
@Slf4j
public class MethodCallHandler extends SimpleChannelInboundHandler<YrpcRequest> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, YrpcRequest yrpcRequest) throws Exception {
        // 1、获取负载内容
        RequestPayload requestPayload = yrpcRequest.getRequestPayload();
            // 2、根据负载内容进行方法调用
        Object result = callTargetMethod(requestPayload);
            if (log.isDebugEnabled()){
                log.debug("请求：{}已经在服务端完成方法调用",yrpcRequest.getRequestId());
            }


        // 3、封装相应
        YrpcResponse yrpcResponse = YrpcResponse.builder()
                .responseCode(ResponseCode.SUCCESS.getCode())
                .requestId(yrpcRequest.getRequestId())
                .compressType(yrpcRequest.getCompressType())
                .serializeType(yrpcRequest.getSerializeType())
                .body(result)
                .build();


        // 4、写出相应
        ctx.channel().writeAndFlush(yrpcResponse);
    }

    private Object callTargetMethod(RequestPayload requestPayload) {
        // 如果是心跳检测,说明他是没有负载的
        if (requestPayload == null){
            return null;
        }
        String methodName = requestPayload.getMethodName();
        String interfaceName = requestPayload.getInterfaceName();
        Class<?>[] parametersType = requestPayload.getParametersType();
        Object[] parametersValue = requestPayload.getParametersValue();

        // 寻找合适的暴露出去的具体的实现
        ServiceConfig<?> serviceConfig = YrpcBootstrap.SERVERS_LIST.get(interfaceName);
        if (serviceConfig == null ){
            log.info("得到的实现为空");
            return null;
        }
        Object refImpl = serviceConfig.getRef();

        // 通过反射调用 1、获取方法对象， 2、执行invoke方法
        Object returnValue = null;
        try {
            Class<?> aClass = refImpl.getClass();
            Method method = aClass.getMethod(methodName, parametersType);
            returnValue = method.invoke(refImpl, parametersValue);
        } catch(InvocationTargetException | IllegalAccessException | NoSuchMethodException e){
            log.error("调用服务{}的方法{}时出现异常",interfaceName,methodName);
            throw new RuntimeException(e);
        }

        return returnValue;
    }
}
